package bayes;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import text.Text;
import text.TextSet;
import text.TextSetManager;
import text.traversal.ComputeProbaClass;
import text.traversal.ComputeProbaOccurence;
import bayes.traversal.GetBestClass;

public class NaiveBayesMultiClass
{
	private TextSetManager	textManager	= new TextSetManager(NaiveBayesMultiClass.class.getCanonicalName());

	public TextSetManager getTextSetManager()
	{
		return this.textManager;
	}

	public NaiveBayesMultiClass()
	{

	}

	public void learn(List<TextSet> textSetList, double coeffLaplace)
	{
		for (TextSet textSet : textSetList)
		{
			this.textManager.addTextSet(textSet);
		}

		this.computeProbaOccurence(coeffLaplace);
		this.computeProbaClass();
	}

	public boolean test(Text text, String className)
	{
		TextSet bestTextSet = this.getBestClass(text);

		return bestTextSet.getName().equals(className);
	}

	public TextSet getBestClass(Text text)
	{
		GetBestClass traversal = new GetBestClass(text);

		this.textManager.traversal(traversal);

		return traversal.getBestClass();
	}

	private void computeProbaOccurence(double coeffLaplace)
	{
		System.out.print("Compute proba occurence ( coeff laplace = "
				+ coeffLaplace + ")...");
		ComputeProbaOccurence traversal = new ComputeProbaOccurence(
				coeffLaplace);
		this.textManager.traversalAllTextSet(traversal);
		this.textManager.traversal(traversal);
		System.out.println("done");
	}

	private void computeProbaClass()
	{
		System.out.print("Compute proba class...");
		this.textManager.traversalAllTextSet(new ComputeProbaClass());
		System.out.println("done");
	}
	
	public static Map<String, String> getTranslationMap(String filename) throws IOException
	{
		final Map<String, String> translationMap = new Hashtable<String, String>();
		
		BufferedReader bufferedReader = new BufferedReader(new FileReader(filename));

		String line;
		while ((line = bufferedReader.readLine()) != null)
		{
			String textToSplit = line.trim();

			if (textToSplit.isEmpty())
			{
				continue;
			}

			String[] stringTab = textToSplit.split("\\W+");

			if(stringTab.length < 2)
			{
				continue;
			}
			
			if(!stringTab[0].equals("class"))
			{
				continue;
			}
			
			String className = "class" + stringTab[1];
			
			for (int i = 2; i < stringTab.length; i++)
			{
				translationMap.put(stringTab[i], className);
			}
		}		
		
		return translationMap;
	}

	public static void main(String[] args) throws IOException
	{
		final String newLine = System.getProperty("line.separator");
		final String separator = ";";
		String result = "test" + separator + "coeff laplace" + separator + "ok" + separator + "ko"
				+ separator + newLine;
		final double coeffLaplaceStep = 1d;
		final double maxCoeffLaplace = 10;
		final double ratioForTesting = 0.1d;

		final File directory = new File("./ressource/20news-bydate-supervised/");
		final File[] subfiles = directory.listFiles();
		final int testStepCount = (int) (1d / ratioForTesting);
		final int coeffLaplaceStepCount = (int) (maxCoeffLaplace / coeffLaplaceStep);
		final Map<String, String> translationMap = getTranslationMap("./ressource/100 classes.txt");
		for (int j = 0; j < testStepCount; j++)
		{
			final double startRatio = j * ratioForTesting;
			
			for (int k = 0; k <= coeffLaplaceStepCount; k++)
			{
				System.gc();
				
				final double coeffLaplace = k * coeffLaplaceStep;
				
				System.out.println("test part " + (j + 1) + " / "
						+ testStepCount + " : ");
				final NaiveBayesMultiClass bayes = new NaiveBayesMultiClass();
				double endRatio = Math.min(startRatio + ratioForTesting, 1);
				List<TextSet> textSetList = new LinkedList<TextSet>();
				System.out.print("reading files [ 0 - " + startRatio + " | "
						+ endRatio + " - 1 ]...");
				for (int i = 0; i < subfiles.length; i++)
				{
					final File file = subfiles[i];
					if (file.isDirectory())
					{
						continue;
					}
					final TextSet textSet = new TextSet(file.getName(), bayes
							.getTextSetManager());
					textSet.parseZip(file.getAbsolutePath(), 0d, startRatio,
							true, translationMap);
					textSet
							.parseZip(file.getAbsolutePath(), endRatio, 1d,
									true, translationMap);
					textSetList.add(textSet);
				}
				System.out.println("done");
				bayes.learn(textSetList, coeffLaplace);

				int ok = 0;
				int ko = 0;
				System.out.print("testing files [" + startRatio + " - "
						+ endRatio + "]...");
				for (int i = 0; i < subfiles.length; i++)
				{
					File file = subfiles[i];
					if (file.isDirectory())
					{
						continue;
					}
					final TextSet textSet = new TextSet(file.getName(), bayes
							.getTextSetManager());
					textSet.parseZip(file.getAbsolutePath(), startRatio,
							endRatio, false, translationMap);

					for (Text text : textSet.getTextList())
					{
						if (bayes.test(text, textSet.getName()))
						{
							ok++;
						}
						else
						{
							ko++;
						}
					}
				}
				System.out.println("done");
				final int total = ok + ko;
				final double okPercent = ((double) ok / (double) total);
				final double koPercent = ((double) ko / (double) total);
				System.out.println(ok + " ok : " + okPercent + " | " + ko
						+ " ko : " + koPercent);
				result += (j + 1) + separator + coeffLaplace + separator + okPercent + separator
						+ koPercent + separator + newLine;
			}
		}

		System.out.println("results : " + newLine + result);
	}
}
